package com.hellobike.haxing.modules.operate.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hellobike.haxing.common.constant.CacheConstant;
import com.hellobike.haxing.common.util.RedisUtil;
import com.hellobike.haxing.modules.coupon.entity.Coupon;
import com.hellobike.haxing.modules.coupon.mapper.CouponMapper;
import com.hellobike.haxing.modules.operate.dto.cms.*;
import com.hellobike.haxing.modules.operate.entity.OperateCmsPage;
import com.hellobike.haxing.modules.operate.entity.OperateCmsPageComponent;
import com.hellobike.haxing.modules.operate.enums.PageComponentParamTypeEnum;
import com.hellobike.haxing.modules.operate.enums.PageComponentStyleEnum;
import com.hellobike.haxing.modules.operate.enums.PageComponentTypeEnum;
import com.hellobike.haxing.modules.operate.exception.CmsServiceException;
import com.hellobike.haxing.modules.operate.mapper.OperateCmsPageComponentMapper;
import com.hellobike.haxing.modules.operate.mapper.OperateCmsPageMapper;
import com.hellobike.haxing.modules.operate.service.IOperateCmsPageService;
import com.hellobike.haxing.modules.operate.vo.*;
import com.hellobike.haxing.modules.product.entity.Category;
import com.hellobike.haxing.modules.product.entity.Product;
import com.hellobike.haxing.modules.product.mapper.CategoryMapper;
import com.hellobike.haxing.modules.product.mapper.ProductMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: t_operate_cms_page
 * @Author: haxing-boot
 * @Date: 2020-02-09
 * @Version: V1.0
 */
@Slf4j
@Service
public class OperateCmsPageServiceImpl extends ServiceImpl<OperateCmsPageMapper, OperateCmsPage> implements IOperateCmsPageService {

    @Autowired
    private OperateCmsPageMapper operateCmsPageMapper;
    @Autowired
    private OperateCmsPageComponentMapper operateCmsPageComponentMapper;
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private CouponMapper couponMapper;
    @Autowired
    private RedisUtil redisUtil;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void save(PageReqDto pageReqDto) throws CmsServiceException {
        Assert.hasText(pageReqDto.getPageName(), "pageName 不能为空");
        Assert.hasText(pageReqDto.getPageTitle(), "pageTitle 不能为空");
        Assert.hasText(pageReqDto.getPageBgColor(), "pageBgColor 不能为空");
        Assert.notEmpty(pageReqDto.getPageComponentList(), "页面组件不能空");
        List<PageComponentReqDto> dtoList = pageReqDto.getPageComponentList();
        for (PageComponentReqDto e : dtoList) {
            JSONArray jsonArray = e.getComponentInfo();
            Assert.notEmpty(jsonArray, "页面组件信息不能空");
            for (int i = 0; i < jsonArray.size(); i++) {
                JSON json = jsonArray.getJSONObject(i);
                if (e.getComponentType() == PageComponentTypeEnum.A) {
                    try {
                        PageComponentPic pageComponentPic = json.toJavaObject(PageComponentPic.class);
                        Assert.hasText(pageComponentPic.getPicUrl(), "picUrl 不能为空");
                        int paramType = pageComponentPic.getParamType();
                        Assert.state(paramType == 0 || paramType == 1 || paramType == 2, "paramType 必须为 [0,1,2]");
                        //Assert.state(pageComponentPic.getPicWidth() > 0 && pageComponentPic.getPicHigh() > 0, "图片高和宽必须大于0");
                        if (paramType == 1) {
                            Assert.hasText(pageComponentPic.getUrl(), "跳转参数url内容不能为空");
                        }
                        if (paramType == 2) {
                            Assert.state(pageComponentPic.getProductId() != null && pageComponentPic.getProductId() > 0,
                                    "跳转参数 请选择商品");
                        }
                    } catch (Exception e1) {
                        log.error("", e1);
                        throw new CmsServiceException("图片json对象格式不正确 " + e1.getMessage());
                    }
                }
                if (e.getComponentType() == PageComponentTypeEnum.B) {
                    try {
                        PageComponentCoupon coupon = json.toJavaObject(PageComponentCoupon.class);
                        Assert.state(coupon.getId() > 0, "优惠券id必须大于0");
                    } catch (Exception e1) {
                        log.error("", e1);
                        throw new CmsServiceException("优惠券json对象格式不正确 " + e1.getMessage());
                    }
                }
                if (e.getComponentType() == PageComponentTypeEnum.C) {
                    try {
                        PageComponentSpu product = json.toJavaObject(PageComponentSpu.class);
                        Assert.state(product.getId() > 0, "商品id必须大于0");
                    } catch (Exception e1) {
                        log.error("", e1);
                        throw new CmsServiceException("商品json对象格式不正确 " + e1.getMessage());
                    }
                }
            }
        }

        OperateCmsPage operateCmsPage = new OperateCmsPage();
        operateCmsPage.setPageName(pageReqDto.getPageName());
        operateCmsPage.setPageTitle(pageReqDto.getPageTitle());
        operateCmsPage.setPageDesc(pageReqDto.getPageDesc());
        operateCmsPage.setPageBgColor(pageReqDto.getPageBgColor());
        operateCmsPage.setPageUrl("");
        operateCmsPage.setShareTitle(pageReqDto.getShareTitle());
        operateCmsPage.setSharePicUrl(pageReqDto.getSharePicUrl());
        boolean flag = false;
        if (pageReqDto.getId() != null && pageReqDto.getId() > 0) {
            Assert.notNull(this.getById(pageReqDto.getId()), "page对象不存在");
            //清除缓存
            redisUtil.del(CacheConstant.OPERATE_CMS_PAGE+pageReqDto.getId());
            operateCmsPage.setId(pageReqDto.getId());
            flag = this.updateById(operateCmsPage);
            //删除原来组件关系
            QueryWrapper<OperateCmsPageComponent> wrapper = new QueryWrapper();
            wrapper.eq("page_id", pageReqDto.getId());
            operateCmsPageComponentMapper.delete(wrapper);
        } else {
            flag = this.save(operateCmsPage);
        }
        if (!flag) {
            throw new CmsServiceException("保存cms page主表失败");
        }

        for (PageComponentReqDto dto : dtoList) {
            OperateCmsPageComponent pageComponent = new OperateCmsPageComponent();
            pageComponent.setPageId(operateCmsPage.getId());
            pageComponent.setComponentType(dto.getComponentType().getValue());
            pageComponent.setComponentStyle(dto.getComponentStyle().getValue());
            pageComponent.setComponentSort(dto.getComponentSort());
            if (dto.getComponentType() != PageComponentTypeEnum.A) {
                List<PageComponentCoupon> list = dto.getComponentInfo().toJavaList(PageComponentCoupon.class);
                //升序
                list.sort(Comparator.comparing(obj -> obj.getIndex()));
                pageComponent.setComponentInfoJsonb(JSONArray.parseArray(JSONArray.toJSONString(list)));
            } else {
                pageComponent.setComponentInfoJsonb(dto.getComponentInfo());
            }
            int flag1 = operateCmsPageComponentMapper.insert(pageComponent);
            if (flag1 != 1) {
                throw new CmsServiceException("保存CmsPageComponent 子表失败");
            }
        }
    }

    @Override
    public PageVo getByPageId(Long id) {
        PageVo pageVo = new PageVo();
        List<ComponentInfo> component = new ArrayList<>();
        pageVo.setComponentList(component);
        OperateCmsPage operateCmsPage = operateCmsPageMapper.selectById(id);
        if (operateCmsPage == null) return null;
        pageVo.setPageName(operateCmsPage.getPageName());
        pageVo.setPageTitle(operateCmsPage.getPageTitle());
        pageVo.setPageBgColor(operateCmsPage.getPageBgColor());
        QueryWrapper<OperateCmsPageComponent> wrapper = new QueryWrapper();
        wrapper.eq("page_id", id);
        List<OperateCmsPageComponent> componentList = operateCmsPageComponentMapper.selectList(wrapper);
        if (componentList.size() == 0) return pageVo;
        componentList.sort(Comparator.comparing(obj -> obj.getComponentSort()));
        for (OperateCmsPageComponent e : componentList) {
            int type = e.getComponentType();
            if (type == PageComponentTypeEnum.A.getValue()) {
                ComponentInfo componentInfo = new ComponentInfo();
                List<PicInfo> picInfoList = new ArrayList<>();
                PicInfo picInfo = new PicInfo();
                JSONArray jsonArray = e.getComponentInfoJsonb();
                JSONObject jsonObject = jsonArray.getJSONObject(0);
                PageComponentPic pageComponentPic = jsonObject.toJavaObject(PageComponentPic.class);
                picInfo.setPicUrl(pageComponentPic.getPicUrl());
                picInfo.setPicHigh(pageComponentPic.getPicHigh());
                picInfo.setPicWidth(pageComponentPic.getPicWidth());
                picInfo.setParamType(pageComponentPic.getParamType());
                picInfo.setUrl(pageComponentPic.getUrl());
                picInfo.setProductId(pageComponentPic.getProductId());
                if (pageComponentPic.getParamType() == PageComponentParamTypeEnum.C.getValue()
                        && pageComponentPic.getProductId() != null) {
                    Product product = productMapper.selectById(pageComponentPic.getProductId());
                    picInfo.setProductName(product.getTitle());
                }
                picInfoList.add(picInfo);
                componentInfo.setComponentStyle(PageComponentStyleEnum.getByValue(e.getComponentStyle()));
                componentInfo.setComponentType(PageComponentTypeEnum.getByValue(type));
                componentInfo.setComponentSort(e.getComponentSort());
                componentInfo.setList(picInfoList);
                component.add(componentInfo);
            }
            if (type == PageComponentTypeEnum.B.getValue()) {
                ComponentInfo componentInfo = new ComponentInfo();
                JSONArray jsonArray = e.getComponentInfoJsonb();
                List<PageComponentCoupon> coupons = jsonArray.toJavaList(PageComponentCoupon.class);
                List<CouponInfo> listCouponInfo = new ArrayList<>();
                for (int i = 0; i < coupons.size(); i++) {
                    CouponInfo couponInfo = new CouponInfo();
                    PageComponentCoupon cn = coupons.get(i);
                    couponInfo.setIndex(cn.getIndex());
                    Coupon coupon = couponMapper.selectById(cn.getId());
                    couponInfo.setId(coupon.getId());
                    couponInfo.setName(coupon.getName());
                    couponInfo.setFaceValue(coupon.getFaceValue());
                    couponInfo.setRequireAmount(coupon.getRequireAmount());
                    couponInfo.setSiteRange(coupon.getSiteRange());
                    couponInfo.setTimeLimitRule(coupon.getTimeLimitRule());
                    listCouponInfo.add(couponInfo);
                }
                componentInfo.setComponentStyle(PageComponentStyleEnum.getByValue(e.getComponentStyle()));
                componentInfo.setComponentType(PageComponentTypeEnum.getByValue(type));
                componentInfo.setComponentSort(e.getComponentSort());
                componentInfo.setList(listCouponInfo);
                component.add(componentInfo);
            }
            if (type == PageComponentTypeEnum.C.getValue()) {
                ComponentInfo componentInfo = new ComponentInfo();
                JSONArray jsonArray = e.getComponentInfoJsonb();
                List<PageComponentSpu> spuIds = jsonArray.toJavaList(PageComponentSpu.class);
                List<ProductInfo> listProductInfo = new ArrayList<>();
                for (int i = 0; i < spuIds.size(); i++) {
                    ProductInfo productInfo = new ProductInfo();
                    PageComponentSpu spu = spuIds.get(i);
                    productInfo.setIndex(spu.getIndex());
                    Product product = productMapper.selectById(spu.getId());
                    productInfo.setId(product.getId());
                    productInfo.setTitle(product.getTitle());
                    productInfo.setMainImage(product.getMainImage());
                    productInfo.setCategoryId1(product.getCategoryId1());
                    productInfo.setCategoryId2(product.getCategoryId2());
                    productInfo.setCategoryId3(product.getCategoryId3());
                    listProductInfo.add(productInfo);
                }
                fillCategoryNames(listProductInfo);
                componentInfo.setComponentStyle(PageComponentStyleEnum.getByValue(e.getComponentStyle()));
                componentInfo.setComponentType(PageComponentTypeEnum.getByValue(type));
                componentInfo.setComponentSort(e.getComponentSort());
                componentInfo.setList(listProductInfo);
                component.add(componentInfo);
            }
        }
        return pageVo;
    }

    private void fillCategoryNames(List<ProductInfo> productList) {
        if (productList != null && productList.size() > 0) {
            Set<Long> categoryIds = new HashSet<>();
            productList.forEach(product -> {
                categoryIds.add(product.getCategoryId1());
                categoryIds.add(product.getCategoryId2());
                categoryIds.add(product.getCategoryId3());
            });
            List<Category> categoryList = categoryMapper.selectBatchIds(categoryIds);
            Map<Long, String> categoryNameMap = categoryList.stream().collect(Collectors.toMap(Category::getId, Category::getName));
            productList.forEach(product -> {
                product.setCategoryName1(categoryNameMap.get(product.getCategoryId1()));
                product.setCategoryName2(categoryNameMap.get(product.getCategoryId2()));
                product.setCategoryName3(categoryNameMap.get(product.getCategoryId3()));
            });
        }
    }
}
